home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Archives / GNU / groff_src.lha / groff-1.10src / pic / lex.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-22  |  39.2 KB  |  1,940 lines

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
  3.      Written by James Clark (jjc@jclark.com)
  4.  
  5. This file is part of groff.
  6.  
  7. groff is free software; you can redistribute it and/or modify it under
  8. the terms of the GNU General Public License as published by the Free
  9. Software Foundation; either version 2, or (at your option) any later
  10. version.
  11.  
  12. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  13. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License along
  18. with groff; see the file COPYING.  If not, write to the Free Software
  19. Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  20.  
  21. #include "pic.h"
  22. #include "ptable.h"
  23. #include "object.h"
  24. #include "pic.tab.h"
  25.  
  26. declare_ptable(char)
  27. implement_ptable(char)
  28.  
  29. PTABLE(char) macro_table;
  30.  
  31. class macro_input : public input {
  32.   char *s;
  33.   char *p;
  34. public:
  35.   macro_input(const char *);
  36.   ~macro_input();
  37.   int get();
  38.   int peek();
  39. };
  40.  
  41. class argument_macro_input : public input {
  42.   char *s;
  43.   char *p;
  44.   char *ap;
  45.   int argc;
  46.   char *argv[9];
  47. public:
  48.   argument_macro_input(const char *, int, char **);
  49.   ~argument_macro_input();
  50.   int get();
  51.   int peek();
  52. };
  53.  
  54. input::input() : next(0)
  55. {
  56. }
  57.  
  58. input::~input()
  59. {
  60. }
  61.  
  62. int input::get_location(const char **, int *)
  63. {
  64.   return 0;
  65. }
  66.  
  67. file_input::file_input(FILE *f, const char *fn)
  68. : lineno(0), ptr(""), filename(fn)
  69. {
  70.   fp = f;
  71. }
  72.  
  73. file_input::~file_input()
  74. {
  75.   fclose(fp);
  76. }
  77.  
  78. int file_input::read_line()
  79. {
  80.   for (;;) {
  81.     line.clear();
  82.     lineno++;
  83.     for (;;) {
  84.       int c = getc(fp);
  85.       if (c == EOF)
  86.     break;
  87.       else if (illegal_input_char(c))
  88.     lex_error("illegal input character code %1", c);
  89.       else {
  90.     line += char(c);
  91.     if (c == '\n') 
  92.       break;
  93.       }
  94.     }
  95.     if (line.length() == 0)
  96.       return 0;
  97.     if (!(line.length() >= 3 && line[0] == '.' && line[1] == 'P'
  98.       && (line[2] == 'S' || line[2] == 'E' || line[2] == 'F')
  99.       && (line.length() == 3 || line[3] == ' ' || line[3] == '\n'
  100.           || compatible_flag))) {
  101.       line += '\0';
  102.       ptr = line.contents();
  103.       return 1;
  104.     }
  105.   }
  106. }
  107.  
  108. int file_input::get()
  109. {
  110.   if (*ptr != '\0' || read_line())
  111.     return (unsigned char)*ptr++;
  112.   else
  113.     return EOF;
  114. }
  115.  
  116. int file_input::peek()
  117. {
  118.   if (*ptr != '\0' || read_line())
  119.     return (unsigned char)*ptr;
  120.   else
  121.     return EOF;
  122. }
  123.  
  124. int file_input::get_location(const char **fnp, int *lnp)
  125. {
  126.   *fnp = filename;
  127.   *lnp = lineno;
  128.   return 1;
  129. }
  130.  
  131. macro_input::macro_input(const char *str)
  132. {
  133.   p = s = strsave(str);
  134. }
  135.  
  136. macro_input::~macro_input()
  137. {
  138.   a_delete s;
  139. }
  140.  
  141. int macro_input::get()
  142. {
  143.   if (p == 0 || *p == '\0')
  144.     return EOF;
  145.   else
  146.     return (unsigned char)*p++;
  147. }
  148.  
  149. int macro_input::peek()
  150. {
  151.   if (p == 0 || *p == '\0')
  152.     return EOF;
  153.   else
  154.     return (unsigned char)*p;
  155. }
  156.  
  157. // Character representing $1.  Must be illegal input character.
  158. #define ARG1 14
  159.  
  160. char *process_body(const char *body)
  161. {
  162.   char *s = strsave(body);
  163.   int j = 0;
  164.   for (int i = 0; s[i] != '\0'; i++)
  165.     if (s[i] == '$' && s[i+1] >= '0' && s[i+1] <= '9') {
  166.       if (s[i+1] != '0')
  167.     s[j++] = ARG1 + s[++i] - '1';
  168.     }
  169.     else
  170.       s[j++] = s[i];
  171.   s[j] = '\0';
  172.   return s;
  173. }
  174.  
  175.  
  176. argument_macro_input::argument_macro_input(const char *body, int ac, char **av)
  177. : argc(ac), ap(0)
  178. {
  179.   for (int i = 0; i < argc; i++)
  180.     argv[i] = av[i];
  181.   p = s = process_body(body);
  182. }
  183.  
  184.  
  185. argument_macro_input::~argument_macro_input()
  186. {
  187.   for (int i = 0; i < argc; i++)
  188.     a_delete argv[i];
  189.   a_delete s;
  190. }
  191.  
  192. int argument_macro_input::get()
  193. {
  194.   if (ap) {
  195.     if (*ap != '\0')
  196.       return (unsigned char)*ap++;
  197.     ap = 0;
  198.   }
  199.   if (p == 0)
  200.     return EOF;
  201.   while (*p >= ARG1 && *p <= ARG1 + 8) {
  202.     int i = *p++ - ARG1;
  203.     if (i < argc && argv[i] != 0 && argv[i][0] != '\0') {
  204.       ap = argv[i];
  205.       return (unsigned char)*ap++;
  206.     }
  207.   }
  208.   if (*p == '\0')
  209.     return EOF;
  210.   return (unsigned char)*p++;
  211. }
  212.  
  213. int argument_macro_input::peek()
  214. {
  215.   if (ap) {
  216.     if (*ap != '\0')
  217.       return (unsigned char)*ap;
  218.     ap = 0;
  219.   }
  220.   if (p == 0)
  221.     return EOF;
  222.   while (*p >= ARG1 && *p <= ARG1 + 8) {
  223.     int i = *p++ - ARG1;
  224.     if (i < argc && argv[i] != 0 && argv[i][0] != '\0') {
  225.       ap = argv[i];
  226.       return (unsigned char)*ap;
  227.     }
  228.   }
  229.   if (*p == '\0')
  230.     return EOF;
  231.   return (unsigned char)*p;
  232. }
  233.  
  234. class input_stack {
  235.   static input *current_input;
  236.   static int bol_flag;
  237. public:
  238.   static void push(input *);
  239.   static void clear();
  240.   static int get_char();
  241.   static int peek_char();
  242.   static int get_location(const char **fnp, int *lnp);
  243.   static void push_back(unsigned char c, int was_bol = 0);
  244.   static int bol();
  245. };
  246.  
  247. input *input_stack::current_input = 0;
  248. int input_stack::bol_flag = 0;
  249.  
  250. inline int input_stack::bol()
  251. {
  252.   return bol_flag;
  253. }
  254.  
  255. void input_stack::clear()
  256. {
  257.   while (current_input != 0) {
  258.     input *tem = current_input;
  259.     current_input = current_input->next;
  260.     delete tem;
  261.   }
  262.   bol_flag = 1;
  263. }
  264.  
  265. void input_stack::push(input *in)
  266. {
  267.   in->next = current_input;
  268.   current_input = in;
  269. }
  270.  
  271. void lex_init(input *top)
  272. {
  273.   input_stack::clear();
  274.   input_stack::push(top);
  275. }
  276.  
  277. void lex_cleanup()
  278. {
  279.   while (input_stack::get_char() != EOF)
  280.     ;
  281. }
  282.  
  283. int input_stack::get_char()
  284. {
  285.   while (current_input != 0) {
  286.     int c = current_input->get();
  287.     if (c != EOF) {
  288.       bol_flag = c == '\n';
  289.       return c;
  290.     }
  291.     // don't pop the top-level input off the stack
  292.     if (current_input->next == 0)
  293.       return EOF;
  294.     input *tem = current_input;
  295.     current_input = current_input->next;
  296.     delete tem;
  297.   }
  298.   return EOF;
  299. }
  300.  
  301. int input_stack::peek_char()
  302. {
  303.   while (current_input != 0) {
  304.     int c = current_input->peek();
  305.     if (c != EOF)
  306.       return c;
  307.     if (current_input->next == 0)
  308.       return EOF;
  309.     input *tem = current_input;
  310.     current_input = current_input->next;
  311.     delete tem;
  312.   }
  313.   return EOF;
  314. }
  315.  
  316. class char_input : public input {
  317.   int c;
  318. public:
  319.   char_input(int);
  320.   int get();
  321.   int peek();
  322. };
  323.  
  324. char_input::char_input(int n) : c((unsigned char)n)
  325. {
  326. }
  327.  
  328. int char_input::get()
  329. {
  330.   int n = c;
  331.   c = EOF;
  332.   return n;
  333. }
  334.  
  335. int char_input::peek()
  336. {
  337.   return c;
  338. }
  339.  
  340. void input_stack::push_back(unsigned char c, int was_bol)
  341. {
  342.   push(new char_input(c));
  343.   bol_flag = was_bol;
  344. }
  345.  
  346. int input_stack::get_location(const char **fnp, int *lnp)
  347. {
  348.   for (input *p = current_input; p; p = p->next)
  349.     if (p->get_location(fnp, lnp))
  350.       return 1;
  351.   return 0;
  352. }
  353.  
  354. string context_buffer;
  355.  
  356. string token_buffer;
  357. double token_double;
  358. int token_int;
  359.  
  360. void interpolate_macro_with_args(const char *body)
  361. {
  362.   char *argv[9];
  363.   int argc = 0;
  364.   int i;
  365.   for (i = 0; i < 9; i++)
  366.     argv[i] = 0;
  367.   int level = 0;
  368.   int c;
  369.   enum { NORMAL, IN_STRING, IN_STRING_QUOTED } state = NORMAL;
  370.   do {
  371.     token_buffer.clear();
  372.     for (;;) {
  373.       c = input_stack::get_char();
  374.       if (c == EOF) {
  375.     lex_error("end of input while scanning macro arguments");
  376.     break;
  377.       }
  378.       if (state == NORMAL && level == 0 && (c == ',' || c == ')')) {
  379.     if (token_buffer.length() > 0) {
  380.       token_buffer +=  '\0';
  381.       argv[argc] = strsave(token_buffer.contents());
  382.     }
  383.     // for `foo()', argc = 0
  384.     if (argc > 0 || c != ')' || i > 0)
  385.       argc++;
  386.     break;
  387.       }
  388.       token_buffer += char(c);
  389.       switch (state) {
  390.       case NORMAL:
  391.     if (c == '"')
  392.       state = IN_STRING;
  393.     else if (c == '(')
  394.       level++;
  395.     else if (c == ')')
  396.       level--;
  397.     break;
  398.       case IN_STRING:
  399.     if (c == '"')
  400.       state = NORMAL;
  401.     else if (c == '\\')
  402.       state = IN_STRING_QUOTED;
  403.     break;
  404.       case IN_STRING_QUOTED:
  405.     state = IN_STRING;
  406.     break;
  407.       }
  408.     }
  409.   } while (c != ')' && c != EOF);
  410.   input_stack::push(new argument_macro_input(body, argc, argv));
  411. }
  412.  
  413. static int docmp(const char *s1, int n1, const char *s2, int n2)
  414. {
  415.   if (n1 < n2) {
  416.     int r = memcmp(s1, s2, n1);
  417.     return r ? r : -1;
  418.   }
  419.   else if (n1 > n2) {
  420.     int r = memcmp(s1, s2, n2);
  421.     return r ? r : 1;
  422.   }
  423.   else
  424.     return memcmp(s1, s2, n1);
  425. }
  426.  
  427. int lookup_keyword(const char *str, int len)
  428. {
  429.   static struct keyword {
  430.     const char *name;
  431.     int token;
  432.   } table[] = {
  433.     { "Here", HERE },
  434.     { "above", ABOVE },
  435.     { "aligned", ALIGNED },
  436.     { "and", AND },
  437.     { "arc", ARC },
  438.     { "arrow", ARROW },
  439.     { "at", AT },
  440.     { "atan2", ATAN2 },
  441.     { "below", BELOW },
  442.     { "between", BETWEEN },
  443.     { "bottom", BOTTOM },
  444.     { "box", BOX },
  445.     { "by", BY },
  446.     { "ccw", CCW },
  447.     { "center", CENTER },
  448.     { "chop", CHOP },
  449.     { "circle", CIRCLE },
  450.     { "command", COMMAND },
  451.     { "copy", COPY },
  452.     { "cos", COS },
  453.     { "cw", CW },
  454.     { "dashed", DASHED },
  455.     { "define", DEFINE },
  456.     { "diam", DIAMETER },
  457.     { "diameter", DIAMETER },
  458.     { "do", DO },
  459.     { "dotted", DOTTED },
  460.     { "down", DOWN },
  461.     { "ellipse", ELLIPSE },
  462.     { "else", ELSE },
  463.     { "end", END },
  464.     { "exp", EXP },
  465.     { "fill", FILL },
  466.     { "filled", FILL },
  467.     { "for", FOR },
  468.     { "from", FROM },
  469.     { "height", HEIGHT },
  470.     { "ht", HEIGHT },
  471.     { "if", IF },
  472.     { "int", INT },
  473.     { "invis", INVISIBLE },
  474.     { "invisible", INVISIBLE },
  475.     { "last", LAST },
  476.     { "left", LEFT },
  477.     { "line", LINE },
  478.     { "ljust", LJUST },
  479.     { "log", LOG },
  480.     { "lower", LOWER },
  481.     { "max", K_MAX },
  482.     { "min", K_MIN },
  483.     { "move", MOVE },
  484.     { "of", OF },
  485.     { "plot", PLOT },
  486.     { "print", PRINT },
  487.     { "rad", RADIUS },
  488.     { "radius", RADIUS },
  489.     { "rand", RAND },
  490.     { "reset", RESET },
  491.     { "right", RIGHT },
  492.     { "rjust", RJUST },
  493.     { "same", SAME },
  494.     { "sh", SH },
  495.     { "sin", SIN },
  496.     { "spline", SPLINE },
  497.     { "sprintf", SPRINTF },
  498.     { "sqrt", SQRT },
  499.     { "start", START },
  500.     { "the", THE },
  501.     { "then", THEN },
  502.     { "thick", THICKNESS },
  503.     { "thickness", THICKNESS },
  504.     { "thru", THRU },
  505.     { "to", TO },
  506.     { "top", TOP },
  507.     { "undef", UNDEF },
  508.     { "until", UNTIL },
  509.     { "up", UP },
  510.     { "upper", UPPER },
  511.     { "way", WAY },
  512.     { "wid", WIDTH },
  513.     { "width", WIDTH },
  514.     { "with", WITH },
  515.   };
  516.   
  517.   const keyword *start = table;
  518.   const keyword *end = table + sizeof(table)/sizeof(table[0]);
  519.   while (start < end) {
  520.     // start <= target < end
  521.     const keyword *mid = start + (end - start)/2;
  522.     
  523.     int cmp = docmp(str, len, mid->name, strlen(mid->name));
  524.     if (cmp == 0)
  525.       return mid->token;
  526.     if (cmp < 0)
  527.       end = mid;
  528.     else
  529.       start = mid + 1;
  530.   }
  531.   return 0;
  532. }
  533.  
  534. int get_token_after_dot(int c)
  535. {
  536.   // get_token deals with the case where c is a digit
  537.   switch (c) {
  538.   case 'h':
  539.     input_stack::get_char();
  540.     c = input_stack::peek_char();
  541.     if (c == 't') {
  542.       input_stack::get_char();
  543.       context_buffer = ".ht";
  544.       return DOT_HT;
  545.     }
  546.     else if (c == 'e') {
  547.       input_stack::get_char();
  548.       c = input_stack::peek_char();
  549.       if (c == 'i') {
  550.     input_stack::get_char();
  551.     c = input_stack::peek_char();
  552.     if (c == 'g') {
  553.       input_stack::get_char();
  554.       c = input_stack::peek_char();
  555.       if (c == 'h') {
  556.         input_stack::get_char();
  557.         c = input_stack::peek_char();
  558.         if (c == 't') {
  559.           input_stack::get_char();
  560.           context_buffer = ".height";
  561.           return DOT_HT;
  562.         }
  563.         input_stack::push_back('h');
  564.       }
  565.       input_stack::push_back('g');
  566.     }
  567.     input_stack::push_back('i');
  568.       }
  569.       input_stack::push_back('e');
  570.     }
  571.     input_stack::push_back('h');
  572.     return '.';
  573.   case 'x':
  574.     input_stack::get_char();
  575.     context_buffer = ".x";
  576.     return DOT_X;
  577.   case 'y':
  578.     input_stack::get_char();
  579.     context_buffer = ".y";
  580.     return DOT_Y;
  581.   case 'c':
  582.     input_stack::get_char();
  583.     c = input_stack::peek_char();
  584.     if (c == 'e') {
  585.       input_stack::get_char();
  586.       c = input_stack::peek_char();
  587.       if (c == 'n') {
  588.     input_stack::get_char();
  589.     c = input_stack::peek_char();
  590.     if (c == 't') {
  591.       input_stack::get_char();
  592.       c = input_stack::peek_char();
  593.       if (c == 'e') {
  594.         input_stack::get_char();
  595.         c = input_stack::peek_char();
  596.         if (c == 'r') {
  597.           input_stack::get_char();
  598.           context_buffer = ".center";
  599.           return DOT_C;
  600.         }
  601.         input_stack::push_back('e');
  602.       }
  603.       input_stack::push_back('t');
  604.     }
  605.     input_stack::push_back('n');
  606.       }
  607.       input_stack::push_back('e');
  608.     }
  609.     context_buffer = ".c";
  610.     return DOT_C;
  611.   case 'n':
  612.     input_stack::get_char();
  613.     c = input_stack::peek_char();
  614.     if (c == 'e') {
  615.       input_stack::get_char();
  616.       context_buffer = ".ne";
  617.       return DOT_NE;
  618.     }
  619.     else if (c == 'w') {
  620.       input_stack::get_char();
  621.       context_buffer = ".nw";
  622.       return DOT_NW;
  623.     }
  624.     else {
  625.       context_buffer = ".n";
  626.       return DOT_N;
  627.     }
  628.     break;
  629.   case 'e':
  630.     input_stack::get_char();
  631.     c = input_stack::peek_char();
  632.     if (c == 'n') {
  633.       input_stack::get_char();
  634.       c = input_stack::peek_char();
  635.       if (c == 'd') {
  636.     input_stack::get_char();
  637.     context_buffer = ".end";
  638.     return DOT_END;
  639.       }
  640.       input_stack::push_back('n');
  641.       context_buffer = ".e";
  642.       return DOT_E;
  643.     }
  644.     context_buffer = ".e";
  645.     return DOT_E;
  646.   case 'w':
  647.     input_stack::get_char();
  648.     c = input_stack::peek_char();
  649.     if (c == 'i') {
  650.       input_stack::get_char();
  651.       c = input_stack::peek_char();
  652.       if (c == 'd') {
  653.     input_stack::get_char();
  654.     c = input_stack::peek_char();
  655.     if (c == 't') {
  656.       input_stack::get_char();
  657.       c = input_stack::peek_char();
  658.       if (c == 'h') {
  659.         input_stack::get_char();
  660.         context_buffer = ".width";
  661.         return DOT_WID;
  662.       }
  663.       input_stack::push_back('t');
  664.     }
  665.     context_buffer = ".wid";
  666.     return DOT_WID;
  667.       }
  668.       input_stack::push_back('i');
  669.     }
  670.     context_buffer = ".w";
  671.     return DOT_W;
  672.   case 's':
  673.     input_stack::get_char();
  674.     c = input_stack::peek_char();
  675.     if (c == 'e') {
  676.       input_stack::get_char();
  677.       context_buffer = ".se";
  678.       return DOT_SE;
  679.     }
  680.     else if (c == 'w') {
  681.       input_stack::get_char();
  682.       context_buffer = ".sw";
  683.       return DOT_SW;
  684.     }
  685.     else {
  686.       if (c == 't') {
  687.     input_stack::get_char();
  688.     c = input_stack::peek_char();
  689.     if (c == 'a') {
  690.       input_stack::get_char();
  691.       c = input_stack::peek_char();
  692.       if (c == 'r') {
  693.         input_stack::get_char();
  694.         c = input_stack::peek_char();
  695.         if (c == 't') {
  696.           input_stack::get_char();
  697.           context_buffer = ".start";
  698.           return DOT_START;
  699.         }
  700.         input_stack::push_back('r');
  701.       }
  702.       input_stack::push_back('a');
  703.     }
  704.     input_stack::push_back('t');
  705.       }
  706.       context_buffer = ".s";
  707.       return DOT_S;
  708.     }
  709.     break;
  710.   case 't':
  711.     input_stack::get_char();
  712.     c = input_stack::peek_char();
  713.     if (c == 'o') {
  714.       input_stack::get_char();
  715.       c = input_stack::peek_char();
  716.       if (c == 'p') {
  717.     input_stack::get_char();
  718.     context_buffer = ".top";
  719.     return DOT_N;
  720.       }
  721.       input_stack::push_back('o');
  722.     }
  723.     context_buffer = ".t";
  724.     return DOT_N;
  725.   case 'l':
  726.     input_stack::get_char();
  727.     c = input_stack::peek_char();
  728.     if (c == 'e') {
  729.       input_stack::get_char();
  730.       c = input_stack::peek_char();
  731.       if (c == 'f') {
  732.     input_stack::get_char();
  733.     c = input_stack::peek_char();
  734.     if (c == 't') {
  735.       input_stack::get_char();
  736.       context_buffer = ".left";
  737.       return DOT_W;
  738.     }
  739.     input_stack::push_back('f');
  740.       }
  741.       input_stack::push_back('e');
  742.     }
  743.     context_buffer = ".l";
  744.     return DOT_W;
  745.   case 'r':
  746.     input_stack::get_char();
  747.     c = input_stack::peek_char();
  748.     if (c == 'a') {
  749.       input_stack::get_char();
  750.       c = input_stack::peek_char();
  751.       if (c == 'd') {
  752.     input_stack::get_char();
  753.     context_buffer = ".rad";
  754.     return DOT_RAD;
  755.       }
  756.       input_stack::push_back('a');
  757.     }
  758.     else if (c == 'i') {
  759.       input_stack::get_char();
  760.       c = input_stack::peek_char();
  761.       if (c == 'g') {
  762.     input_stack::get_char();
  763.     c = input_stack::peek_char();
  764.     if (c == 'h') {
  765.       input_stack::get_char();
  766.       c = input_stack::peek_char();
  767.       if (c == 't') {
  768.         input_stack::get_char();
  769.         context_buffer = ".right";
  770.         return DOT_E;
  771.       }
  772.       input_stack::push_back('h');
  773.     }
  774.     input_stack::push_back('g');
  775.       }
  776.       input_stack::push_back('i');
  777.     }
  778.     context_buffer = ".r";
  779.     return DOT_E;
  780.   case 'b':
  781.     input_stack::get_char();
  782.     c = input_stack::peek_char();
  783.     if (c == 'o') {
  784.       input_stack::get_char();
  785.       c = input_stack::peek_char();
  786.       if (c == 't') {
  787.     input_stack::get_char();
  788.     c = input_stack::peek_char();
  789.     if (c == 't') {
  790.       input_stack::get_char();
  791.       c = input_stack::peek_char();
  792.       if (c == 'o') {
  793.         input_stack::get_char();
  794.         c = input_stack::peek_char();
  795.         if (c == 'm') {
  796.           input_stack::get_char();
  797.           context_buffer = ".bottom";
  798.           return DOT_S;
  799.         }
  800.         input_stack::push_back('o');
  801.       }
  802.       input_stack::push_back('t');
  803.     }
  804.     context_buffer = ".bot";
  805.     return DOT_S;
  806.       }
  807.       input_stack::push_back('o');
  808.     }
  809.     context_buffer = ".b";
  810.     return DOT_S;
  811.   default:
  812.     context_buffer = '.';
  813.     return '.';
  814.   }
  815. }
  816.  
  817. int get_token(int lookup_flag)
  818. {
  819.   context_buffer.clear();
  820.   for (;;) {
  821.     int n = 0;
  822.     int bol = input_stack::bol();
  823.     int c = input_stack::get_char();
  824.     if (bol && c == command_char) {
  825.       token_buffer.clear();
  826.       token_buffer += c;
  827.       // the newline is not part of the token
  828.       for (;;) {
  829.     c = input_stack::peek_char();
  830.     if (c == EOF || c == '\n')
  831.       break;
  832.     input_stack::get_char();
  833.     token_buffer += char(c);
  834.       }
  835.       context_buffer = token_buffer;
  836.       return COMMAND_LINE;
  837.     }
  838.     switch (c) {
  839.     case EOF:
  840.       return EOF;
  841.     case ' ':
  842.     case '\t':
  843.       break;
  844.     case '\\':
  845.       {
  846.     int d = input_stack::peek_char();
  847.     if (d != '\n') {
  848.       context_buffer = '\\';
  849.       return '\\';
  850.     }
  851.     input_stack::get_char();
  852.     break;
  853.       }
  854.     case '#':
  855.       do {
  856.     c = input_stack::get_char();
  857.       } while (c != '\n' && c != EOF);
  858.       if (c == '\n')
  859.     context_buffer = '\n';
  860.       return c;
  861.     case '"':
  862.       context_buffer = '"';
  863.       token_buffer.clear();
  864.       for (;;) {
  865.     c = input_stack::get_char();
  866.     if (c == '\\') {
  867.       context_buffer += '\\';
  868.       c = input_stack::peek_char();
  869.       if (c == '"') {
  870.         input_stack::get_char();
  871.         token_buffer += '"';
  872.         context_buffer += '"';
  873.       }
  874.       else
  875.         token_buffer += '\\';
  876.     }
  877.     else if (c == '\n') {
  878.       error("newline in string");
  879.       break;
  880.     }
  881.     else if (c == EOF) {
  882.       error("missing `\"'");
  883.       break;
  884.     }
  885.     else if (c == '"') {
  886.       context_buffer += '"';
  887.       break;
  888.     }
  889.     else {
  890.       context_buffer += char(c);
  891.       token_buffer += char(c);
  892.     }
  893.       }
  894.       return TEXT;
  895.     case '0':
  896.     case '1':
  897.     case '2':
  898.     case '3':
  899.     case '4':
  900.     case '5':
  901.     case '6':
  902.     case '7':
  903.     case '8':
  904.     case '9':
  905.       {   
  906.     int overflow = 0;
  907.     n = 0;
  908.     for (;;) {
  909.       if (n > (INT_MAX - 9)/10) {
  910.         overflow = 1;
  911.         break;
  912.       }
  913.       n *= 10;
  914.       n += c - '0';
  915.       context_buffer += char(c);
  916.       c = input_stack::peek_char();
  917.       if (c == EOF || !csdigit(c))
  918.         break;
  919.       c = input_stack::get_char();
  920.     }
  921.     token_double = n;
  922.     if (overflow) {
  923.       for (;;) {
  924.         token_double *= 10.0;
  925.         token_double += c - '0';
  926.         context_buffer += char(c);
  927.         c = input_stack::peek_char();
  928.         if (c == EOF || !csdigit(c))
  929.           break;
  930.         c = input_stack::get_char();
  931.       }
  932.       // if somebody asks for 1000000000000th, we will silently
  933.       // give them INT_MAXth
  934.       double temp = token_double; // work around gas 1.34/sparc bug
  935.       if (token_double > INT_MAX)
  936.         n = INT_MAX;
  937.       else
  938.         n = int(temp);
  939.     }
  940.       }
  941.       switch (c) {
  942.       case 'i':
  943.       case 'I':
  944.     context_buffer += char(c);
  945.     input_stack::get_char();
  946.     return NUMBER;
  947.       case '.':
  948.     {
  949.       context_buffer += '.';
  950.       input_stack::get_char();
  951.     got_dot:
  952.       double factor = 1.0;
  953.       for (;;) {
  954.         c = input_stack::peek_char();
  955.         if (!c == EOF || !csdigit(c))
  956.           break;
  957.         input_stack::get_char();
  958.         context_buffer += char(c);
  959.         factor /= 10.0;
  960.         if (c != '0')
  961.           token_double += factor*(c - '0');
  962.       }
  963.       if (c != 'e' && c != 'E') {
  964.         if (c == 'i' || c == 'I') {
  965.           context_buffer += char(c);
  966.           input_stack::get_char();
  967.         }
  968.         return NUMBER;
  969.       }
  970.     }
  971.     // fall through
  972.       case 'e':
  973.       case 'E':
  974.     {
  975.       int echar = c;
  976.       input_stack::get_char();
  977.       c = input_stack::peek_char();
  978.       int sign = '+';
  979.       if (c == '+' || c == '-') {
  980.         sign = c;
  981.         input_stack::get_char();
  982.         c = input_stack::peek_char();
  983.         if (c == EOF || !csdigit(c)) {
  984.           input_stack::push_back(sign);
  985.           input_stack::push_back(echar);
  986.           return NUMBER;
  987.         }
  988.         context_buffer += char(echar);
  989.         context_buffer += char(sign);
  990.       }
  991.       else {
  992.         if (c == EOF || !csdigit(c)) {
  993.           input_stack::push_back(echar);
  994.           return NUMBER;
  995.         }
  996.         context_buffer += char(echar);
  997.       }
  998.       input_stack::get_char();
  999.       context_buffer += char(c);
  1000.       n = c - '0';
  1001.       for (;;) {
  1002.         c = input_stack::peek_char();
  1003.         if (c == EOF || !csdigit(c))
  1004.           break;
  1005.         input_stack::get_char();
  1006.         context_buffer += char(c);
  1007.         n = n*10 + (c - '0');
  1008.       }
  1009.       if (sign == '-')
  1010.         n = -n;
  1011.       if (c == 'i' || c == 'I') {
  1012.         context_buffer += char(c);
  1013.         input_stack::get_char();
  1014.       }
  1015.       token_double *= pow(10.0, n);
  1016.       return NUMBER;
  1017.     }
  1018.       case 'n':
  1019.     input_stack::get_char();
  1020.     c = input_stack::peek_char();
  1021.     if (c == 'd') {
  1022.       input_stack::get_char();
  1023.       token_int = n;
  1024.       context_buffer += "nd";
  1025.       return ORDINAL;
  1026.     }
  1027.     input_stack::push_back('n');
  1028.     return NUMBER;
  1029.       case 'r':
  1030.     input_stack::get_char();
  1031.     c = input_stack::peek_char();
  1032.     if (c == 'd') {
  1033.       input_stack::get_char();
  1034.       token_int = n;
  1035.       context_buffer += "rd";
  1036.       return ORDINAL;
  1037.     }
  1038.     input_stack::push_back('r');
  1039.     return NUMBER;
  1040.       case 't':
  1041.     input_stack::get_char();
  1042.     c = input_stack::peek_char();
  1043.     if (c == 'h') {
  1044.       input_stack::get_char();
  1045.       token_int = n;
  1046.       context_buffer += "th";
  1047.       return ORDINAL;
  1048.     }
  1049.     input_stack::push_back('t');
  1050.     return NUMBER;
  1051.       case 's':
  1052.     input_stack::get_char();
  1053.     c = input_stack::peek_char();
  1054.     if (c == 't') {
  1055.       input_stack::get_char();
  1056.       token_int = n;
  1057.       context_buffer += "st";
  1058.       return ORDINAL;
  1059.     }
  1060.     input_stack::push_back('s');
  1061.     return NUMBER;
  1062.       default:
  1063.     return NUMBER;
  1064.       }
  1065.       break;
  1066.     case '\'':
  1067.       {
  1068.     c = input_stack::peek_char();
  1069.     if (c == 't') {
  1070.       input_stack::get_char();
  1071.       c = input_stack::peek_char();
  1072.       if (c == 'h') {
  1073.         input_stack::get_char();
  1074.         context_buffer = "'th";
  1075.         return TH;
  1076.       }
  1077.       else
  1078.         input_stack::push_back('t');
  1079.     }
  1080.     context_buffer = "'";
  1081.     return '\'';
  1082.       }
  1083.     case '.':
  1084.       {
  1085.     c = input_stack::peek_char();
  1086.     if (c != EOF && csdigit(c)) {
  1087.       n = 0;
  1088.       token_double = 0.0;
  1089.       context_buffer = '.';
  1090.       goto got_dot;
  1091.     }
  1092.     return get_token_after_dot(c);
  1093.       }
  1094.     case '<':
  1095.       c = input_stack::peek_char();
  1096.       if (c == '-') {
  1097.     input_stack::get_char();
  1098.     c = input_stack::peek_char();
  1099.     if (c == '>') {
  1100.       input_stack::get_char();
  1101.       context_buffer = "<->";
  1102.       return DOUBLE_ARROW_HEAD;
  1103.     }
  1104.     context_buffer = "<-";
  1105.     return LEFT_ARROW_HEAD;
  1106.       }
  1107.       else if (c == '=') {
  1108.     input_stack::get_char();
  1109.     context_buffer = "<=";
  1110.     return LESSEQUAL;
  1111.       }
  1112.       context_buffer = "<";
  1113.       return '<';
  1114.     case '-':
  1115.       c = input_stack::peek_char();
  1116.       if (c == '>') {
  1117.     input_stack::get_char();
  1118.     context_buffer = "->";
  1119.     return RIGHT_ARROW_HEAD;
  1120.       }
  1121.       context_buffer = "-";
  1122.       return '-';
  1123.     case '!':
  1124.       c = input_stack::peek_char();
  1125.       if (c == '=') {
  1126.     input_stack::get_char();
  1127.     context_buffer = "!=";
  1128.     return NOTEQUAL;
  1129.       }
  1130.       context_buffer = "!";
  1131.       return '!';
  1132.     case '>':
  1133.       c = input_stack::peek_char();
  1134.       if (c == '=') {
  1135.     input_stack::get_char();
  1136.     context_buffer = ">=";
  1137.     return GREATEREQUAL;
  1138.       }
  1139.       context_buffer = ">";
  1140.       return '>';
  1141.     case '=':
  1142.       c = input_stack::peek_char();
  1143.       if (c == '=') {
  1144.     input_stack::get_char();
  1145.     context_buffer = "==";
  1146.     return EQUALEQUAL;
  1147.       }
  1148.       context_buffer = "=";
  1149.       return '=';
  1150.     case '&':
  1151.       c = input_stack::peek_char();
  1152.       if (c == '&') {
  1153.     input_stack::get_char();
  1154.     context_buffer = "&&";
  1155.     return ANDAND;
  1156.       }
  1157.       context_buffer = "&";
  1158.       return '&';
  1159.     case '|':
  1160.       c = input_stack::peek_char();
  1161.       if (c == '|') {
  1162.     input_stack::get_char();
  1163.     context_buffer = "||";
  1164.     return OROR;
  1165.       }
  1166.       context_buffer = "|";
  1167.       return '|';
  1168.     default:
  1169.       if (c != EOF && csalpha(c)) {
  1170.     token_buffer.clear();
  1171.     token_buffer = c;
  1172.     for (;;) {
  1173.       c = input_stack::peek_char();
  1174.       if (c == EOF || (!csalnum(c) && c != '_'))
  1175.         break;
  1176.       input_stack::get_char();
  1177.       token_buffer += char(c);
  1178.     }
  1179.     int tok = lookup_keyword(token_buffer.contents(),
  1180.                  token_buffer.length());
  1181.     if (tok != 0) {
  1182.       context_buffer = token_buffer;
  1183.       return tok;
  1184.     }
  1185.     char *def = 0;
  1186.     if (lookup_flag) {
  1187.       token_buffer += '\0';
  1188.       def = macro_table.lookup(token_buffer.contents());
  1189.       token_buffer.set_length(token_buffer.length() - 1);
  1190.       if (def) {
  1191.         if (c == '(') {
  1192.           input_stack::get_char();
  1193.           interpolate_macro_with_args(def);
  1194.         }
  1195.         else
  1196.           input_stack::push(new macro_input(def));
  1197.       }
  1198.     }
  1199.     if (!def) {
  1200.       context_buffer = token_buffer;
  1201.       if (csupper(token_buffer[0]))
  1202.         return LABEL;
  1203.       else
  1204.         return VARIABLE;
  1205.     }
  1206.       }
  1207.       else {
  1208.     context_buffer = char(c);
  1209.     return (unsigned char)c;
  1210.       }
  1211.       break;
  1212.     }
  1213.   }
  1214. }
  1215.  
  1216. int get_delimited()
  1217. {
  1218.   token_buffer.clear();
  1219.   int c = input_stack::get_char();
  1220.   while (c == ' ' || c == '\t' || c == '\n')
  1221.     c = input_stack::get_char();
  1222.   if (c == EOF) {
  1223.     lex_error("missing delimiter");
  1224.     return 0;
  1225.   }
  1226.   context_buffer = char(c);
  1227.   int had_newline = 0;
  1228.   int start = c;
  1229.   int level = 0;
  1230.   enum { NORMAL, IN_STRING, IN_STRING_QUOTED, DELIM_END } state = NORMAL;
  1231.   for (;;) {
  1232.     c = input_stack::get_char();
  1233.     if (c == EOF) {
  1234.       lex_error("missing closing delimiter");
  1235.       return 0;
  1236.     }
  1237.     if (c == '\n')
  1238.       had_newline = 1;
  1239.     else if (!had_newline)
  1240.       context_buffer += char(c);
  1241.     switch (state) {
  1242.     case NORMAL:
  1243.       if (start == '{') {
  1244.     if (c == '{') {
  1245.       level++;
  1246.       break;
  1247.     }
  1248.     if (c == '}') {
  1249.       if (--level < 0)
  1250.         state = DELIM_END;
  1251.       break;
  1252.     }
  1253.       }
  1254.       else {
  1255.     if (c == start) {
  1256.       state = DELIM_END;
  1257.       break;
  1258.     }
  1259.       }
  1260.       if (c == '"')
  1261.     state = IN_STRING;
  1262.       break;
  1263.     case IN_STRING_QUOTED:
  1264.       if (c == '\n')
  1265.     state = NORMAL;
  1266.       else
  1267.     state = IN_STRING;
  1268.       break;
  1269.     case IN_STRING:
  1270.       if (c == '"' || c == '\n')
  1271.     state = NORMAL;
  1272.       else if (c == '\\')
  1273.     state = IN_STRING_QUOTED;
  1274.       break;
  1275.     case DELIM_END:
  1276.       // This case it just to shut cfront 2.0 up.
  1277.     default:
  1278.       assert(0);
  1279.     }
  1280.     if (state == DELIM_END)
  1281.       break;
  1282.     token_buffer += c;
  1283.   }
  1284.   return 1;
  1285. }
  1286.  
  1287. void do_define()
  1288. {
  1289.   int t = get_token(0);        // do not expand what we are defining
  1290.   if (t != VARIABLE && t != LABEL) {
  1291.     lex_error("can only define variable or placename");
  1292.     return;
  1293.   }
  1294.   token_buffer += '\0';
  1295.   string nm = token_buffer;
  1296.   const char *name = nm.contents();
  1297.   if (!get_delimited())
  1298.     return;
  1299.   token_buffer += '\0';
  1300.   macro_table.define(name, strsave(token_buffer.contents()));
  1301. }
  1302.  
  1303. void do_undef()
  1304. {
  1305.   int t = get_token(0);        // do not expand what we are undefining
  1306.   if (t != VARIABLE && t != LABEL) {
  1307.     lex_error("can only define variable or placename");
  1308.     return;
  1309.   }
  1310.   token_buffer += '\0';
  1311.   macro_table.define(token_buffer.contents(), 0);
  1312. }
  1313.  
  1314.  
  1315. class for_input : public input {
  1316.   char *var;
  1317.   char *body;
  1318.   double to;
  1319.   int by_is_multiplicative;
  1320.   double by;
  1321.   const char *p;
  1322.   int done_newline;
  1323. public:
  1324.   for_input(char *, double, int, double, char *);
  1325.   ~for_input();
  1326.   int get();
  1327.   int peek();
  1328. };
  1329.  
  1330. for_input::for_input(char *vr, double t, int bim, double b, char *bd)
  1331. : var(vr), to(t), by_is_multiplicative(bim), by(b), body(bd), p(body),
  1332.   done_newline(0)
  1333. {
  1334. }
  1335.  
  1336. for_input::~for_input()
  1337. {
  1338.   a_delete var;
  1339.   a_delete body;
  1340. }
  1341.  
  1342. int for_input::get()
  1343. {
  1344.   if (p == 0)
  1345.     return EOF;
  1346.   for (;;) {
  1347.     if (*p != '\0')
  1348.       return (unsigned char)*p++;
  1349.     if (!done_newline) {
  1350.       done_newline = 1;
  1351.       return '\n';
  1352.     }
  1353.     double val;
  1354.     if (!lookup_variable(var, &val)) {
  1355.       lex_error("body of `for' terminated enclosing block");
  1356.       return EOF;
  1357.     }
  1358.     if (by_is_multiplicative)
  1359.       val *= by;
  1360.     else
  1361.       val += by;
  1362.     define_variable(var, val);
  1363.     if (val > to) {
  1364.       p = 0;
  1365.       return EOF;
  1366.     }
  1367.     p = body;
  1368.     done_newline = 0;
  1369.   }
  1370. }
  1371.  
  1372. int for_input::peek()
  1373. {
  1374.   if (p == 0)
  1375.     return EOF;
  1376.   if (*p != '\0')
  1377.     return (unsigned char)*p;
  1378.   if (!done_newline)
  1379.     return '\n';
  1380.   double val;
  1381.   if (!lookup_variable(var, &val))
  1382.     return EOF;
  1383.   if (by_is_multiplicative) {
  1384.     if (val * by > to)
  1385.       return EOF;
  1386.   }
  1387.   else {
  1388.     if (val + by > to)
  1389.       return EOF;
  1390.   }
  1391.   if (*body == '\0')
  1392.     return EOF;
  1393.   return (unsigned char)*body;
  1394. }
  1395.  
  1396. void do_for(char *var, double from, double to, int by_is_multiplicative,
  1397.         double by, char *body)
  1398. {
  1399.   define_variable(var, from);
  1400.   if (from <= to)
  1401.     input_stack::push(new for_input(var, to, by_is_multiplicative, by, body));
  1402. }
  1403.  
  1404.  
  1405. void do_copy(const char *filename)
  1406. {
  1407.   errno = 0;
  1408.   FILE *fp = fopen(filename, "r");
  1409.   if (fp == 0) {
  1410.     lex_error("can't open `%1': %2", filename, strerror(errno));
  1411.     return;
  1412.   }
  1413.   input_stack::push(new file_input(fp, filename));
  1414. }
  1415.  
  1416. class copy_thru_input : public input {
  1417.   int done;
  1418.   char *body;
  1419.   char *until;
  1420.   const char *p;
  1421.   const char *ap;
  1422.   int argv[9];
  1423.   int argc;
  1424.   string line;
  1425.   int get_line();
  1426.   virtual int inget() = 0;
  1427. public:
  1428.   copy_thru_input(const char *b, const char *u);
  1429.   ~copy_thru_input();
  1430.   int get();
  1431.   int peek();
  1432. };
  1433.  
  1434. class copy_file_thru_input : public copy_thru_input {
  1435.   input *in;
  1436. public:
  1437.   copy_file_thru_input(input *, const char *b, const char *u);
  1438.   ~copy_file_thru_input();
  1439.   int inget();
  1440. };
  1441.  
  1442. copy_file_thru_input::copy_file_thru_input(input *i, const char *b,
  1443.                        const char *u)
  1444. : in(i), copy_thru_input(b, u)
  1445. {
  1446. }
  1447.  
  1448. copy_file_thru_input::~copy_file_thru_input()
  1449. {
  1450.   delete in;
  1451. }
  1452.  
  1453. int copy_file_thru_input::inget()
  1454. {
  1455.   if (!in)
  1456.     return EOF;
  1457.   else
  1458.     return in->get();
  1459. }
  1460.  
  1461. class copy_rest_thru_input : public copy_thru_input {
  1462. public:
  1463.   copy_rest_thru_input(const char *, const char *u);
  1464.   int inget();
  1465. };
  1466.  
  1467. copy_rest_thru_input::copy_rest_thru_input(const char *b, const char *u)
  1468. : copy_thru_input(b, u)
  1469. {
  1470. }
  1471.  
  1472. int copy_rest_thru_input::inget()
  1473. {
  1474.   while (next != 0) {
  1475.     int c = next->get();
  1476.     if (c != EOF)
  1477.       return c;
  1478.     if (next->next == 0)
  1479.       return EOF;
  1480.     input *tem = next;
  1481.     next = next->next;
  1482.     delete tem;
  1483.   }
  1484.   return EOF;
  1485.  
  1486. }
  1487.  
  1488. copy_thru_input::copy_thru_input(const char *b, const char *u)
  1489. : done(0)
  1490. {
  1491.   ap = 0;
  1492.   body = process_body(b);
  1493.   p = 0;
  1494.   until = strsave(u);
  1495. }
  1496.  
  1497.  
  1498. copy_thru_input::~copy_thru_input()
  1499. {
  1500.   a_delete body;
  1501.   a_delete until;
  1502. }
  1503.  
  1504. int copy_thru_input::get()
  1505. {
  1506.   if (ap) {
  1507.     if (*ap != '\0')
  1508.       return (unsigned char)*ap++;
  1509.     ap = 0;
  1510.   }
  1511.   for (;;) {
  1512.     if (p == 0) {
  1513.       if (!get_line())
  1514.     break;
  1515.       p = body;
  1516.     }
  1517.     if (*p == '\0') {
  1518.       p = 0;
  1519.       return '\n';
  1520.     }
  1521.     while (*p >= ARG1 && *p <= ARG1 + 8) {
  1522.       int i = *p++ - ARG1;
  1523.       if (i < argc && line[argv[i]] != '\0') {
  1524.     ap = line.contents() + argv[i];
  1525.     return (unsigned char)*ap++;
  1526.       }
  1527.     }
  1528.     if (*p != '\0')
  1529.       return (unsigned char)*p++;
  1530.   }
  1531.   return EOF;
  1532. }
  1533.  
  1534. int copy_thru_input::peek()
  1535. {
  1536.   if (ap) {
  1537.     if (*ap != '\0')
  1538.       return (unsigned char)*ap;
  1539.     ap = 0;
  1540.   }
  1541.   for (;;) {
  1542.     if (p == 0) {
  1543.       if (!get_line())
  1544.     break;
  1545.       p = body;
  1546.     }
  1547.     if (*p == '\0')
  1548.       return '\n';
  1549.     while (*p >= ARG1 && *p <= ARG1 + 8) {
  1550.       int i = *p++ - ARG1;
  1551.       if (i < argc && line[argv[i]] != '\0') {
  1552.     ap = line.contents() + argv[i];
  1553.     return (unsigned char)*ap;
  1554.       }
  1555.     }
  1556.     if (*p != '\0')
  1557.       return (unsigned char)*p;
  1558.   }
  1559.   return EOF;
  1560. }
  1561.  
  1562. int copy_thru_input::get_line()
  1563. {
  1564.   if (done)
  1565.     return 0;
  1566.   line.clear();
  1567.   argc = 0;
  1568.   int c = inget();
  1569.   for (;;) {
  1570.     while (c == ' ')
  1571.       c = inget();
  1572.     if (c == EOF || c == '\n')
  1573.       break;
  1574.     if (argc == 9) {
  1575.       do {
  1576.     c = inget();
  1577.       } while (c != '\n' && c != EOF);
  1578.       break;
  1579.     }
  1580.     argv[argc++] = line.length();
  1581.     do {
  1582.       line += char(c);
  1583.       c = inget();
  1584.     } while (c != ' ' && c != '\n');
  1585.     line += '\0';
  1586.   }
  1587.   if (until != 0 && argc > 0 && strcmp(&line[argv[0]], until) == 0) {
  1588.     done = 1;
  1589.     return 0;
  1590.   }
  1591.   return argc > 0 || c == '\n';
  1592. }
  1593.  
  1594. class simple_file_input : public input {
  1595.   const char *filename;
  1596.   int lineno;
  1597.   FILE *fp;
  1598. public:
  1599.   simple_file_input(FILE *, const char *);
  1600.   ~simple_file_input();
  1601.   int get();
  1602.   int peek();
  1603.   int get_location(const char **, int *);
  1604. };
  1605.  
  1606. simple_file_input::simple_file_input(FILE *p, const char *s)
  1607. : filename(s), fp(p), lineno(1)
  1608. {
  1609. }
  1610.  
  1611. simple_file_input::~simple_file_input()
  1612. {
  1613.   // don't delete the filename
  1614.   fclose(fp);
  1615. }
  1616.  
  1617. int simple_file_input::get()
  1618. {
  1619.   int c = getc(fp);
  1620.   while (illegal_input_char(c)) {
  1621.     error("illegal input character code %1", c);
  1622.     c = getc(fp);
  1623.   }
  1624.   if (c == '\n')
  1625.     lineno++;
  1626.   return c;
  1627. }
  1628.  
  1629. int simple_file_input::peek()
  1630. {
  1631.   int c = getc(fp);
  1632.   while (illegal_input_char(c)) {
  1633.     error("illegal input character code %1", c);
  1634.     c = getc(fp);
  1635.   }
  1636.   if (c != EOF)
  1637.     ungetc(c, fp);
  1638.   return c;
  1639. }
  1640.  
  1641. int simple_file_input::get_location(const char **fnp, int *lnp)
  1642. {
  1643.   *fnp = filename;
  1644.   *lnp = lineno;
  1645.   return 1;
  1646. }
  1647.  
  1648.  
  1649. void copy_file_thru(const char *filename, const char *body, const char *until)
  1650. {
  1651.   errno = 0;
  1652.   FILE *fp = fopen(filename, "r");
  1653.   if (fp == 0) {
  1654.     lex_error("can't open `%1': %2", filename, strerror(errno));
  1655.     return;
  1656.   }
  1657.   input *in = new copy_file_thru_input(new simple_file_input(fp, filename),
  1658.                        body, until);
  1659.   input_stack::push(in);
  1660. }
  1661.  
  1662. void copy_rest_thru(const char *body, const char *until)
  1663. {
  1664.   input_stack::push(new copy_rest_thru_input(body, until));
  1665. }
  1666.  
  1667. void push_body(const char *s)
  1668. {
  1669.   input_stack::push(new char_input('\n'));
  1670.   input_stack::push(new macro_input(s));
  1671. }
  1672.  
  1673. int delim_flag = 0;
  1674.  
  1675. char *get_thru_arg()
  1676. {
  1677.   int c = input_stack::peek_char();
  1678.   while (c == ' ') {
  1679.     input_stack::get_char();
  1680.     c = input_stack::peek_char();
  1681.   }
  1682.   if (c != EOF && csalpha(c)) {
  1683.     // looks like a macro
  1684.     input_stack::get_char();
  1685.     token_buffer = c;
  1686.     for (;;) {
  1687.       c = input_stack::peek_char();
  1688.       if (c == EOF || (!csalnum(c) && c != '_'))
  1689.     break;
  1690.       input_stack::get_char();
  1691.       token_buffer += char(c);
  1692.     }
  1693.     context_buffer = token_buffer;
  1694.     token_buffer += '\0';
  1695.     char *def = macro_table.lookup(token_buffer.contents());
  1696.     if (def)
  1697.       return strsave(def);
  1698.     // I guess it wasn't a macro after all; so push the macro name back.
  1699.     // -2 because we added a '\0'
  1700.     for (int i = token_buffer.length() - 2; i >= 0; i--)
  1701.       input_stack::push_back(token_buffer[i]);
  1702.   }
  1703.   if (get_delimited()) {
  1704.     token_buffer += '\0';
  1705.     return strsave(token_buffer.contents());
  1706.   }
  1707.   else
  1708.     return 0;
  1709. }
  1710.  
  1711. int lookahead_token = -1;
  1712. string old_context_buffer;
  1713.  
  1714. void do_lookahead()
  1715. {
  1716.   if (lookahead_token == -1) {
  1717.     old_context_buffer = context_buffer;
  1718.     lookahead_token = get_token(1);
  1719.   }
  1720. }
  1721.  
  1722. int yylex()
  1723. {
  1724.   if (delim_flag) {
  1725.     assert(lookahead_token == -1);
  1726.     if (delim_flag == 2) {
  1727.       if ((yylval.str = get_thru_arg()) != 0)
  1728.     return DELIMITED;
  1729.       else
  1730.     return 0;
  1731.     }
  1732.     else {
  1733.       if (get_delimited()) {
  1734.     token_buffer += '\0';
  1735.     yylval.str = strsave(token_buffer.contents());
  1736.     return DELIMITED;
  1737.       }
  1738.       else
  1739.     return 0;
  1740.     }
  1741.   }
  1742.   for (;;) {
  1743.     int t;
  1744.     if (lookahead_token >= 0) {
  1745.       t = lookahead_token;
  1746.       lookahead_token = -1;
  1747.     }
  1748.     else
  1749.       t = get_token(1);
  1750.     switch (t) {
  1751.     case '\n':
  1752.       return ';';
  1753.     case EOF:
  1754.       return 0;
  1755.     case DEFINE:
  1756.       do_define();
  1757.       break;
  1758.     case UNDEF:
  1759.       do_undef();
  1760.       break;
  1761.     case ORDINAL:
  1762.       yylval.n = token_int;
  1763.       return t;
  1764.     case NUMBER:
  1765.       yylval.x = token_double;
  1766.       return t;
  1767.     case COMMAND_LINE:
  1768.     case TEXT:
  1769.       token_buffer += '\0';
  1770.       if (!input_stack::get_location(&yylval.lstr.filename,
  1771.                      &yylval.lstr.lineno)) {
  1772.     yylval.lstr.filename = 0;
  1773.     yylval.lstr.lineno = -1;
  1774.       }
  1775.       yylval.lstr.str = strsave(token_buffer.contents());
  1776.       return t;
  1777.     case LABEL:
  1778.     case VARIABLE:
  1779.       token_buffer += '\0';
  1780.       yylval.str = strsave(token_buffer.contents());
  1781.       return t;
  1782.     case LEFT:
  1783.       // change LEFT to LEFT_CORNER when followed by OF
  1784.       old_context_buffer = context_buffer;
  1785.       lookahead_token = get_token(1);
  1786.       if (lookahead_token == OF)
  1787.     return LEFT_CORNER;
  1788.       else
  1789.     return t;
  1790.     case RIGHT:
  1791.       // change RIGHT to RIGHT_CORNER when followed by OF
  1792.       old_context_buffer = context_buffer;
  1793.       lookahead_token = get_token(1);
  1794.       if (lookahead_token == OF)
  1795.     return RIGHT_CORNER;
  1796.       else
  1797.     return t;
  1798.     case UPPER:
  1799.       // recognise UPPER only before LEFT or RIGHT
  1800.       old_context_buffer = context_buffer;
  1801.       lookahead_token = get_token(1);
  1802.       if (lookahead_token != LEFT && lookahead_token != RIGHT) {
  1803.     yylval.str = strsave("upper");
  1804.     return VARIABLE;
  1805.       }
  1806.       else
  1807.     return t;
  1808.     case LOWER:
  1809.       // recognise LOWER only before LEFT or RIGHT
  1810.       old_context_buffer = context_buffer;
  1811.       lookahead_token = get_token(1);
  1812.       if (lookahead_token != LEFT && lookahead_token != RIGHT) {
  1813.     yylval.str = strsave("lower");
  1814.     return VARIABLE;
  1815.       }
  1816.       else
  1817.     return t;
  1818.     case TOP:
  1819.       // recognise TOP only before OF
  1820.       old_context_buffer = context_buffer;
  1821.       lookahead_token = get_token(1);
  1822.       if (lookahead_token != OF) {
  1823.     yylval.str = strsave("top");
  1824.     return VARIABLE;
  1825.       }
  1826.       else
  1827.     return t;
  1828.     case BOTTOM:
  1829.       // recognise BOTTOM only before OF
  1830.       old_context_buffer = context_buffer;
  1831.       lookahead_token = get_token(1);
  1832.       if (lookahead_token != OF) {
  1833.     yylval.str = strsave("bottom");
  1834.     return VARIABLE;
  1835.       }
  1836.       else
  1837.     return t;
  1838.     case CENTER:
  1839.       // recognise CENTER only before OF
  1840.       old_context_buffer = context_buffer;
  1841.       lookahead_token = get_token(1);
  1842.       if (lookahead_token != OF) {
  1843.     yylval.str = strsave("center");
  1844.     return VARIABLE;
  1845.       }
  1846.       else
  1847.     return t;
  1848.     case START:
  1849.       // recognise START only before OF
  1850.       old_context_buffer = context_buffer;
  1851.       lookahead_token = get_token(1);
  1852.       if (lookahead_token != OF) {
  1853.     yylval.str = strsave("start");
  1854.     return VARIABLE;
  1855.       }
  1856.       else
  1857.     return t;
  1858.     case END:
  1859.       // recognise END only before OF
  1860.       old_context_buffer = context_buffer;
  1861.       lookahead_token = get_token(1);
  1862.       if (lookahead_token != OF) {
  1863.     yylval.str = strsave("end");
  1864.     return VARIABLE;
  1865.       }
  1866.       else
  1867.     return t;
  1868.     default:
  1869.       return t;
  1870.     }
  1871.   }
  1872. }
  1873.  
  1874. void lex_error(const char *message,
  1875.            const errarg &arg1,
  1876.            const errarg &arg2,
  1877.            const errarg &arg3)
  1878. {
  1879.   const char *filename;
  1880.   int lineno;
  1881.   if (!input_stack::get_location(&filename, &lineno))
  1882.     error(message, arg1, arg2, arg3);
  1883.   else
  1884.     error_with_file_and_line(filename, lineno, message, arg1, arg2, arg3);
  1885. }
  1886.  
  1887. void lex_warning(const char *message,
  1888.          const errarg &arg1,
  1889.          const errarg &arg2,
  1890.          const errarg &arg3)
  1891. {
  1892.   const char *filename;
  1893.   int lineno;
  1894.   if (!input_stack::get_location(&filename, &lineno))
  1895.     warning(message, arg1, arg2, arg3);
  1896.   else
  1897.     warning_with_file_and_line(filename, lineno, message, arg1, arg2, arg3);
  1898. }
  1899.  
  1900. void yyerror(const char *s)
  1901. {
  1902.   const char *filename;
  1903.   int lineno;
  1904.   const char *context = 0;
  1905.   if (lookahead_token == -1) {
  1906.     if (context_buffer.length() > 0) {
  1907.       context_buffer += '\0';
  1908.       context = context_buffer.contents();
  1909.     }
  1910.   }
  1911.   else {
  1912.     if (old_context_buffer.length() > 0) {
  1913.       old_context_buffer += '\0';
  1914.       context = old_context_buffer.contents();
  1915.     }
  1916.   }
  1917.   if (!input_stack::get_location(&filename, &lineno)) {
  1918.     if (context) {
  1919.       if (context[0] == '\n' && context[1] == '\0')
  1920.     error("%1 before newline", s);
  1921.       else
  1922.     error("%1 before `%2'", s, context);
  1923.     }
  1924.     else
  1925.       error("%1 at end of picture", s);
  1926.   }
  1927.   else {
  1928.     if (context) {
  1929.       if (context[0] == '\n' && context[1] == '\0')
  1930.     error_with_file_and_line(filename, lineno, "%1 before newline", s);
  1931.       else
  1932.     error_with_file_and_line(filename, lineno, "%1 before `%2'",
  1933.                  s, context);
  1934.     }
  1935.     else
  1936.       error_with_file_and_line(filename, lineno, "%1 at end of picture", s);
  1937.   }
  1938. }
  1939.  
  1940.